/*
 *  Copyright 2019-2023 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package me.zhengjie.modules.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import javafx.scene.control.Separator;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.exception.BizException;
import me.zhengjie.modules.biz.domain.VolunteerForm;
import me.zhengjie.modules.biz.domain.VolunteerProfession;
import me.zhengjie.modules.biz.domain.dto.MyVolunteerFormDTO;
import me.zhengjie.modules.biz.domain.dto.ProfessionDTO;
import me.zhengjie.modules.biz.domain.req.VolunteerFormReq;
import me.zhengjie.modules.biz.domain.resp.VolunteerFormResp;
import me.zhengjie.modules.biz.domain.resp.WxUserVolunteerResp;
import me.zhengjie.modules.biz.service.VolunteerProfessionService;
import me.zhengjie.utils.FileUtil;
import lombok.RequiredArgsConstructor;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import me.zhengjie.modules.biz.service.VolunteerFormService;
import me.zhengjie.modules.biz.domain.vo.VolunteerFormQueryCriteria;
import me.zhengjie.modules.biz.mapper.VolunteerFormMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import me.zhengjie.utils.PageUtil;


import java.io.File;
import java.util.*;
import java.io.IOException;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;

import me.zhengjie.utils.PageResult;

import static me.zhengjie.modules.biz.constant.GlobalConstant.*;
import static me.zhengjie.modules.biz.domain.enums.ErrorCode.*;
import static me.zhengjie.modules.pay.enums.StatusEnum.*;

/**
 * @description 服务实现
 * @author yiwei.he
 * @date 2024-03-14
 **/

@Service
@RequiredArgsConstructor
@Slf4j
public class VolunteerFormServiceImpl extends ServiceImpl<VolunteerFormMapper, VolunteerForm> implements VolunteerFormService {

    private final VolunteerFormMapper volunteerFormMapper;

    private final VolunteerProfessionService volunteerProfessionService;

    @Value(value = "${url.default}")
    private String logoUrl;


    @Override
    public PageResult<WxUserVolunteerResp> queryAll(VolunteerFormQueryCriteria criteria, Page<Object> page) throws BizException {
        if(criteria.getCategory() == null){
            throw new BizException(BODY_NOTNULL.getCode(),BODY_NOTNULL.getMessage());
        }
        // 1.获取学生的userId,根据category来获取院校的列表
        List<Long> userIds = volunteerFormMapper.qryUserIds(criteria);

        if(criteria.getIsExport() == 0){
            // 分页处理
            int size = (int) page.getSize();
            int current = (int) page.getCurrent();
            int totalSize = userIds.size();

            int startIndex = (current - 1) * size;
            int endIndex = Math.min(startIndex + size, totalSize);
            // 如果起始索引大于结束索引，返回空
            if(startIndex >= endIndex){
                return null;
            }
            // 分页后的ids
            List<Long> pageIds = userIds.subList(startIndex, endIndex);
            if(userIds.isEmpty()){
                return null;
            }
            criteria.setUserIds(pageIds);
        }else {
            criteria.setUserIds(userIds);
            if(userIds.isEmpty()){
                throw new BizException(EXPORT_FAILED.getCode(),EXPORT_FAILED.getMessage());
            }
        }

        List<WxUserVolunteerResp> respList = getWxUserVolunteerRespList(criteria);
        return PageUtil.toPage(respList,userIds.size());
    }

    private List<WxUserVolunteerResp> getWxUserVolunteerRespList(VolunteerFormQueryCriteria criteria) {
        List<WxUserVolunteerResp> respList = new ArrayList<>();

        List<MyVolunteerFormDTO> list = volunteerFormMapper.findAll(criteria);
        Map<String, List<MyVolunteerFormDTO>> userMap = new HashMap<>();
        list.forEach(u -> {
            if (u != null) {
                // 如果院校结果中出现多个【平行志愿1】或【平行志愿A】  ，查询日志---填报志愿时，sort是否为空
                int sort = u.getSort() == null ? 1 : u.getSort();
                String volunteerSort = (criteria.getCategory() == CATEGORY_ZSB) ? String.valueOf(sort) : VOLUNTEER_MAP.get(sort);
                u.setVolunteerSort(VOLUNTEER_NAME + volunteerSort);

                // 初始化userMap,按志愿序号排序
                String key = u.getUsername() + ":" + u.getPhone();
                userMap.computeIfAbsent(key, k -> new ArrayList<>()).add(u);

                List<MyVolunteerFormDTO> sortedVolunteer = userMap.get(key).stream()
                        .sorted(Comparator.comparingInt(dto -> dto.getSort() == null ? 0 : dto.getSort()))
                        .collect(Collectors.toList());
                userMap.put(key, sortedVolunteer);
            }
        });

        // 封装用户的志愿详情
        userMap.forEach((key, value) -> {
            WxUserVolunteerResp resp = new WxUserVolunteerResp();
            String[] split = key.split(":");
            resp.setUsername(split[0]);
            resp.setPhone(split[1]);
            resp.setType(volunteerModuleMap.get(criteria.getCategory()));

            List<String> volunteerList = value.stream()
                    .map(this::buildVolunteerString)
                    .collect(Collectors.toList());

            resp.setVolunteerList(volunteerList);
            respList.add(resp);
        });
        return respList;
    }

    @Override
    public List<WxUserVolunteerResp> queryAll(VolunteerFormQueryCriteria criteria) throws BizException {
        return queryAll(criteria,new Page<>()).getContent();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(VolunteerForm resources) {
        save(resources);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(VolunteerForm resources) {
        VolunteerForm volunteerForm = getById(resources.getId());
        volunteerForm.copy(resources);
        saveOrUpdate(volunteerForm);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAll(List<Long> ids) {
        removeBatchByIds(ids);
    }

    @Override
    public void download(List<WxUserVolunteerResp> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (WxUserVolunteerResp volunteerForm : all) {
            List<String> volunteerList = volunteerForm.getVolunteerList();
            String detail = String.join("\n", volunteerList);
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("账号",volunteerForm.getUsername());
            map.put("手机号",volunteerForm.getPhone());
            map.put("项目类型",volunteerForm.getType());
            map.put("志愿详情",detail);
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }


    /**
     * 保存我的志愿
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addVolunteerForm(VolunteerFormReq req) throws BizException {
        if (req == null) {
            throw new BizException(BODY_NOTNULL.getCode(),BODY_NOTNULL.getMessage());
        }
        // 如果是修改专业，先删除之前的志愿及专业，再进行添加
        if(null != req.getVolunteerId()){
            // 先删专业
            volunteerProfessionService.deleteProfessions(req.getVolunteerId(),req.getCategory());
        }
        // 查询已填报的志愿数量
        Integer volunteerNum = volunteerFormMapper.getVolunteerNum(req);
        if(null == volunteerNum){
            volunteerNum = 0;
        }
        boolean res = false;
        switch (req.getCategory()) {
            case CATEGORY_ZSB:
                if (volunteerNum >= 0 && volunteerNum < 32) {
                    res = addVolunteer(req);
                } else {
                    throw new BizException(NUM_ALREADY_MAX.getCode(),NUM_ALREADY_MAX.getMessage());
                }
                break;
            case CATEGORY_GK:
            case CATEGORY_DZ:
                if (volunteerNum >= 0 && volunteerNum < 9) {
                    res = addVolunteer(req);
                } else {
                    throw new BizException(VOLUNTEER_NUM_ERROR.getCode(),VOLUNTEER_NUM_ERROR.getMessage());
                }
                break;
            default:
                throw new BizException(BODY_NOTNULL.getCode(),BODY_NOTNULL.getMessage());
        }
        return res;
    }

    @Override
    public VolunteerFormResp myVolunteerForm(VolunteerFormQueryCriteria req) throws BizException {
        if (req == null) {
            throw new BizException(BODY_NOTNULL.getCode(),BODY_NOTNULL.getMessage());
        }
        VolunteerFormResp resp = new VolunteerFormResp();
        List<MyVolunteerFormDTO> list = volunteerFormMapper.myVolunteerForm(req).stream().sorted(Comparator.comparingInt(MyVolunteerFormDTO::getSort)).collect(Collectors.toList());
        list.forEach(u ->{
            // 处理院校logo为空和平行志愿的情况
            if(u != null){
                u.setLogo(logoUrl + DEFAULT_LOGO);
                String s = VOLUNTEER_MAP.get(u.getSort());
                u.setVolunteerSort(VOLUNTEER_NAME + s);
                List<ProfessionDTO> pList = u.getProfessionDTOList()
                        .stream()
                        .sorted(Comparator.comparingInt(ProfessionDTO::getProfessionSort))
                        .collect(Collectors.toList());
                u.setProfessionDTOList(pList);
            }
        });
        resp.setContent(list);
        resp.setTotalElements(list.size());
        return resp;
    }

    private boolean addVolunteer(VolunteerFormReq req) throws BizException {
        VolunteerForm volunteerForm = req2VolunteerForm(req);
        // 统招/单招需要判断该院校是否已加入了志愿表  专升本需要判断院校-专业是否加入了志愿表中
        VolunteerForm ans = null;
        // 如果是修改则无需判断
        if(req.getVolunteerId() == null){
            // 检测志愿序号
            checkVolunteerSort(req);
            if (CATEGORY_ZSB == req.getCategory()) {
                ans = volunteerFormMapper.checkForUndergraduate(req);
            } else {
                ans = volunteerFormMapper.checkForOther(req);
            }
            if (ans != null) {
                throw new BizException(NOT_REPETITION_VOLUNTEER.getCode(),NOT_REPETITION_VOLUNTEER.getMessage());
            }
            // 保存志愿
            this.save(volunteerForm);
        }else{
            // 修改志愿
            volunteerForm.setId(req.getVolunteerId());
            volunteerFormMapper.updateById(volunteerForm);
        }
        List<VolunteerProfession> volunteerProfessionList = getVolunteerProfessions(req, volunteerForm);
        volunteerProfessionService.saveBatch(volunteerProfessionList);
        return true;
    }

    private void checkVolunteerSort(VolunteerFormReq req) throws BizException {
        VolunteerForm volunteerSort = volunteerFormMapper.selectOne(new QueryWrapper<VolunteerForm>()
                .eq("sort", req.getSort())
                .eq("category",req.getCategory())
                .eq("user_id", req.getUserId())
        );
        if(volunteerSort != null){
            throw new BizException(VOLUNTEER_SORT_ALREADY_EXIST.getCode(),VOLUNTEER_SORT_ALREADY_EXIST.getMessage());
        }
    }

    private List<VolunteerProfession> getVolunteerProfessions(VolunteerFormReq req, VolunteerForm volunteerForm) throws BizException {
        Long volunteerFormId = volunteerForm.getId();
        // 保存志愿与专业的关系
        List<VolunteerProfession> volunteerProfessionList = new ArrayList<>();
        List<ProfessionDTO> professionList = req.getProfessionList();
        // 判断专业的个数是否异常
        int professionSize = professionList.size();
        if ((req.getCategory() == 2 && professionSize != 1) ||   // 专升本只能填报一个专业
                professionSize < 1 || professionSize > 6) {      // 其他情况下专业个数应在1到6之间
            throw new BizException(VOLUNTEER_NUM_ERROR.getCode(),VOLUNTEER_NUM_ERROR.getMessage());
        }
        professionList.forEach(professionDTO -> {
            volunteerProfessionList.add(dto2VolunteerProfession(professionDTO, req, volunteerFormId));
        });
        return volunteerProfessionList;
    }

    /**
     * 构建单个志愿详情
     */
    private String buildVolunteerString(MyVolunteerFormDTO dto) {
        String status = dto.getStatus() == STATUS_SAFE.getCode() ? STATUS_SAFE.getMessage() : (dto.getStatus() == STATUS_SURE.getCode() ? STATUS_SURE.getMessage() : STATUS_SPRINT.getMessage());
        List<String> professionDetails = dto.getProfessionDTOList().stream()
                .sorted(Comparator.comparingInt(ProfessionDTO::getProfessionSort))
                .map(profession -> " " + profession.getProfessionSort() + "." + profession.getProfession())
                .collect(Collectors.toList());
        String professionDetail = String.join("", professionDetails);
        return dto.getVolunteerSort() + "-" + status + "-" + dto.getUniversitiesName() + "-" + professionDetail;
    }


    private VolunteerForm req2VolunteerForm(VolunteerFormReq req) {
        VolunteerForm volunteerForm = new VolunteerForm();
        volunteerForm.setUserId(req.getUserId());
        volunteerForm.setUniversitiesId(req.getUniversitiesId());
        volunteerForm.setCategory(req.getCategory());
        volunteerForm.setStatus(req.getStatus());
        volunteerForm.setSort(req.getSort());
        volunteerForm.setCreateTime(new Date());
        volunteerForm.setUpdateTime(new Date());
        return volunteerForm;
    }
    private VolunteerProfession dto2VolunteerProfession(ProfessionDTO dto, VolunteerFormReq req, Long volunteerFormId) {
        VolunteerProfession volunteerProfession = new VolunteerProfession();
        volunteerProfession.setProfessionId(dto.getId());
        volunteerProfession.setProfessionSort(dto.getProfessionSort());
        volunteerProfession.setUserId(req.getUserId());
        volunteerProfession.setVolunteerId(volunteerFormId);
        volunteerProfession.setCategory(req.getCategory());
        return volunteerProfession;
    }

}